/**
 * 地理位置工具类
 * 提供统一的地理位置获取和处理功能
 */

import { locationAPI } from '@/api'
import { ElMessage } from 'element-plus'

class LocationUtils {
  constructor() {
    this.currentLocation = null
    this.locationCache = new Map()
    this.cacheTimeout = 5 * 60 * 1000 // 5分钟缓存
  }

  /**
   * 获取用户当前位置
   * @param {Object} options - 配置选项
   * @param {boolean} options.enableHighAccuracy - 是否启用高精度定位
   * @param {number} options.timeout - 超时时间
   * @param {number} options.maximumAge - 缓存时间
   * @param {boolean} options.showMessage - 是否显示消息提示
   * @returns {Promise<Object>} 位置信息
   */
  async getCurrentLocation(options = {}) {
    const {
      enableHighAccuracy = true,
      timeout = 10000,
      maximumAge = 300000, // 5分钟
      showMessage = true
    } = options

    try {
      // 检查缓存
      if (this.currentLocation && this.isLocationCacheValid()) {
        return this.currentLocation
      }

      // 优先使用GPS定位
      if (navigator.geolocation) {
        try {
          const position = await this.getGPSPosition({
            enableHighAccuracy,
            timeout,
            maximumAge
          })

          const { latitude, longitude } = position.coords

          // 逆地理编码获取地址信息
          const locationResponse = await locationAPI.reverseGeocode(latitude, longitude)
          const locationData = {
            ...locationResponse.data,
            source: 'gps',
            accuracy: position.coords.accuracy,
            timestamp: Date.now()
          }

          this.currentLocation = locationData

          if (showMessage) {
            ElMessage.success(`GPS定位成功: ${locationData.address}`)
          }

          return locationData
        } catch (gpsError) {
          console.log('GPS定位失败:', gpsError)
          if (showMessage) {
            // 根据错误类型显示不同的提示信息
            let message = 'GPS定位失败，尝试IP定位'

            if (gpsError.code === 1) {
              message = '需要位置权限，使用IP定位'
            } else if (gpsError.code === 2) {
              message = 'GPS信号不可用，使用IP定位'
            } else if (gpsError.code === 3) {
              message = '定位超时，使用IP定位'
            }

            ElMessage.warning(message)
          }
        }
      }

      // 降级到IP定位
      const ipResponse = await locationAPI.getLocationByIP()
      const locationData = {
        ...ipResponse.data,
        source: 'ip',
        timestamp: Date.now()
      }

      this.currentLocation = locationData

      if (showMessage) {
        ElMessage.info(`IP定位: ${locationData.address}`)
      }

      return locationData

    } catch (error) {
      console.error('定位失败:', error)

      if (showMessage) {
        ElMessage.warning('定位失败，使用默认位置')
      }

      // 返回默认位置
      const defaultLocation = {
        city: '北京',
        province: '北京市',
        country: '中国',
        latitude: 39.9042,
        longitude: 116.4074,
        address: '北京市',
        source: 'default',
        timestamp: Date.now()
      }

      this.currentLocation = defaultLocation
      return defaultLocation
    }
  }

  /**
   * 获取GPS位置
   * @param {Object} options - GPS选项
   * @returns {Promise<Position>} GPS位置
   */
  getGPSPosition(options) {
    return new Promise((resolve, reject) => {
      navigator.geolocation.getCurrentPosition(resolve, reject, options)
    })
  }

  /**
   * 检查位置缓存是否有效
   * @returns {boolean} 是否有效
   */
  isLocationCacheValid() {
    if (!this.currentLocation || !this.currentLocation.timestamp) {
      return false
    }
    return Date.now() - this.currentLocation.timestamp < this.cacheTimeout
  }

  /**
   * 地理编码（地址转坐标）
   * @param {string} address - 地址
   * @returns {Promise<Object>} 位置信息
   */
  async geocode(address) {
    try {
      // 检查缓存
      const cacheKey = `geocode_${address}`
      if (this.locationCache.has(cacheKey)) {
        const cached = this.locationCache.get(cacheKey)
        if (Date.now() - cached.timestamp < this.cacheTimeout) {
          return cached.data
        }
      }

      const response = await locationAPI.geocode(address)
      const locationData = response.data

      // 缓存结果
      this.locationCache.set(cacheKey, {
        data: locationData,
        timestamp: Date.now()
      })

      return locationData
    } catch (error) {
      console.error('地理编码失败:', error)
      throw error
    }
  }

  /**
   * 逆地理编码（坐标转地址）
   * @param {number} lat - 纬度
   * @param {number} lng - 经度
   * @returns {Promise<Object>} 位置信息
   */
  async reverseGeocode(lat, lng) {
    try {
      // 检查缓存
      const cacheKey = `reverse_${lat}_${lng}`
      if (this.locationCache.has(cacheKey)) {
        const cached = this.locationCache.get(cacheKey)
        if (Date.now() - cached.timestamp < this.cacheTimeout) {
          return cached.data
        }
      }

      const response = await locationAPI.reverseGeocode(lat, lng)
      const locationData = response.data

      // 缓存结果
      this.locationCache.set(cacheKey, {
        data: locationData,
        timestamp: Date.now()
      })

      return locationData
    } catch (error) {
      console.error('逆地理编码失败:', error)
      throw error
    }
  }

  /**
   * 搜索地点
   * @param {string} keyword - 搜索关键词
   * @param {string} city - 城市限制
   * @returns {Promise<Array>} 搜索结果
   */
  async searchLocation(keyword, city) {
    try {
      const response = await locationAPI.searchLocation(keyword, city)
      return response.data
    } catch (error) {
      console.error('搜索地点失败:', error)
      throw error
    }
  }

  /**
   * 获取城市列表
   * @returns {Promise<Array>} 城市列表
   */
  async getCities() {
    try {
      // 检查缓存
      const cacheKey = 'cities'
      if (this.locationCache.has(cacheKey)) {
        const cached = this.locationCache.get(cacheKey)
        if (Date.now() - cached.timestamp < this.cacheTimeout) {
          return cached.data
        }
      }

      const response = await locationAPI.getCities()
      const cities = response.data

      // 缓存结果
      this.locationCache.set(cacheKey, {
        data: cities,
        timestamp: Date.now()
      })

      return cities
    } catch (error) {
      console.error('获取城市列表失败:', error)
      throw error
    }
  }

  /**
   * 计算两点间距离（单位：公里）
   * @param {number} lat1 - 第一个点的纬度
   * @param {number} lng1 - 第一个点的经度
   * @param {number} lat2 - 第二个点的纬度
   * @param {number} lng2 - 第二个点的经度
   * @returns {number} 距离（公里）
   */
  calculateDistance(lat1, lng1, lat2, lng2) {
    const R = 6371 // 地球半径（公里）
    const dLat = this.toRadians(lat2 - lat1)
    const dLng = this.toRadians(lng2 - lng1)
    const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
              Math.cos(this.toRadians(lat1)) * Math.cos(this.toRadians(lat2)) *
              Math.sin(dLng / 2) * Math.sin(dLng / 2)
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
    return R * c
  }

  /**
   * 角度转弧度
   * @param {number} degrees - 角度
   * @returns {number} 弧度
   */
  toRadians(degrees) {
    return degrees * (Math.PI / 180)
  }

  /**
   * 清除缓存
   */
  clearCache() {
    this.currentLocation = null
    this.locationCache.clear()
  }

  /**
   * 获取位置参数对象（用于API调用）
   * @param {Object} location - 位置信息
   * @returns {Object} API参数
   */
  getLocationParams(location = null) {
    const loc = location || this.currentLocation
    if (!loc) {
      return { city: '北京' }
    }

    if (loc.latitude && loc.longitude) {
      return {
        lat: loc.latitude,
        lng: loc.longitude
      }
    }

    return { city: loc.city || '北京' }
  }
}

// 创建单例实例
const locationUtils = new LocationUtils()

export default locationUtils
